#!/usr/bin/env python3
# Created by han on 2016/7/4
import socket, sys, os, json
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from module import public

class myclient:
    def __init__(self, ip, port, name=None, size=None):
        self.ip = ip
        self.port = port
        self.name = name
        self.size = size        #每个用户注册后默认的一个大小为1024k

    def cmd(self):
        ip_port = (self.ip, self.port)
        sk = socket.socket()
        sk.connect(ip_port)
        home_name = self.name + "_" + self.size
        sk.sendall(bytes(home_name,"utf8")) #发送用户家目录名字
        recv_data = sk.recv(1024)
        print(recv_data.decode())
        while True:
            cmd_data = input(">>: ").strip() #格式化命令数据
            if not cmd_data:      #如果输入命令为空，则重新输入
                continue
            if cmd_data == "exit":  #如果命令为exit 为退出，终端本次通话
                break
            if not cmd_data.startswith("put") and not cmd_data.startswith("get"):       #如果用户输入的字段不是put或者get开头
                cmd_ret = self.client_shell(sk, cmd_data)     #那就执行ssh的模块
                if cmd_ret:                #如果有返回值，证明命令执行成功
                    print(cmd_ret.decode())   #打印命令的返回值
                else:
                    break           #否则表示有异常，退出本次循环，这个应该不会出现，因为服务器端不会有异常发生，因为客户端这里都做了判断了
            else:                              #用户输入的字段是put或者get开头
                cmd_list = cmd_data.split()     #拆分命令
                if len(cmd_list) < 2:           #如果长度小于2 这名上传或下载的格式不对
                    msg = "type error"
                    public.color_msg(31, msg, 40)
                    continue                    #让用户重新输入
                task_type = cmd_list[0]         #如果不小于2，获取用户的操作类型
                if hasattr(self, "client_%s" % task_type):      #检验这个功能是否存在
                    func = getattr(self, "client_%s" % task_type)   #如果存在则获取这个方法
                    abs_filepath = cmd_list[1]                      #用户要上传的文件
                    if os.path.isfile(abs_filepath):                #判断文件如果存在
                        ret = func(sk, abs_filepath)                      #执行
                        if not ret:
                            continue
                    else:
                        msg = "file not exist"
                        public.color_msg(31, msg, 40)
                else:
                    msg = "unsupported : %s" % task_type
                    public.color_msg(31, msg, 40)
        sk.close()

    def client_register(self, user_info):
        ip_port = (self.ip, self.port)
        sk = socket.socket()
        a = sk.connect(ip_port)                 #接通电话
        user_dict = json.loads(user_info)
        sk.sendall(bytes(user_dict["name"],"utf8"))
        welcome_msg = sk.recv(1024)
        print(welcome_msg.decode())
        sk.sendall(bytes(user_info, "utf8"))               #传送要干的事情
        register_ret = sk.recv(4096)             #接收确认信息
        if register_ret.decode() == "success":
            msg = "register success"
            public.color_msg(32, msg, 40)
            sk.close()


    def client_shell(self, socket_obj, cmd_data):
        """
        执行shell命令的功能
        :param socket_obj:socket对象
        :param cmd_data: 用户输入的命令
        :return: socket server端返回的结果bytes类型
        """
        socket_obj.sendall(bytes(cmd_data, "utf8"))  # 正常就传送命令数据
        ready_data = socket_obj.recv(1024)  # 然后接受准备数据
        raw_data = ready_data.decode()  # 解码准备接收数据
        # print(raw_data)
        if raw_data.startswith("ready"):  # 如果这个数据开头是ready开始的
            raw_len = int(raw_data.split("|")[-1])  # 则获取长度
            client_ready = bytes("start", "utf8")  # 准备开始数据
            socket_obj.sendall(client_ready)  # 发送可以接受数据的信号
            data_len = 0  # 初始化长度
            data = b""  # 初始化数据
            while data_len < raw_len:
                recv_data = socket_obj.recv(1024)  # 循环接受数据
                data_len += len(recv_data)  # 循环增加数据长度
                data += recv_data  # 循环将数据相加
                print("all : %d (byte) , local : %d (byte)" % (raw_len, data_len))      #显示总大小和单次的大小
            return data
        else:
            error_data = socket_obj.recv(1024)
            print(error_data.decode())
            return False

#D:\mydrivers\update\DirectX_Jun2010_redist.exe
#D:\影音\python视频\day9\oldboy-1.avi

    def client_put(self, socket_obj, file):
        """
        上传文件
        :param socket_obj: socket对象
        :param file: 上传的文件
        :return:
        """
        file_size = os.stat(file).st_size           #查看文件的大小
        msg = "Upload File: %s , size: %s\n" % (file, file_size)        #打印文件名称和文件大小
        public.color_msg(36, msg, 50)
        md5 = public.get_file_md5(file)             #计算md5
        # print(md5)
        info = {"action": "put", "name": file, "size": file_size, "md5": md5}   #准备以json格式传输
        file_info = json.dumps(info)
        socket_obj.sendall(bytes(file_info, "utf8"))                            #传输文件信息
        ready_flag = socket_obj.recv(1024)                                      #接收服务器端发来的确认信息，要上传的文件状态
        confirm_data = json.loads(ready_flag.decode())                                   #服务器传来的json
        if confirm_data["status"] == "0":                                       #如果status为0代表文件已经存在且完整
            msg = "file is exist"
            public.color_msg(31, msg, 40)
            return False
        elif confirm_data["status"] == "1":                                     #如果status为1 代表文件不存在
            with open(file,"rb") as file_info:                                  #读取本地文件
                send_size = 0                                                    #初始化文件传输的大小，
                for f in file_info:                                             #循环读文件
                    socket_obj.sendall(f)                                       #传输文件
                    send_size += len(f)                                          #每次将文件的大小相加
                    msg = "[ all size: %s , send size: %s ]\n" % (file_size,send_size)      #打印传输过程
                    public.color_msg(33, msg, 40)
                if send_size == file_size:                                      #如果传输的大小，等于文件大小
                    msg = "send success"                                        #成功
                    public.color_msg(32, msg, 40)
                    return True
                else:
                    msg = " transmission interruption "
                    public.color_msg(31, msg, 40)

        elif confirm_data["status"] == "2":
            position = confirm_data["seek"]                     #获取终端位置
            with open(file,"rb") as file_info:
                file_info.seek(position)                        #将指针移到终端位置
                for i in file_info:                             #循环遍历这个文件
                    socket_obj.sendall(i)                       #开始传输

        elif confirm_data["status"] == "3":                 #如果是3则是文件超出了可以上传的界限
            may_size = confirm_data["max"]                  #获取可上传大小
            file_size = confirm_data["file"]                #获取文件大小
            msg = "Upload Fail --- You May Update [ %s ] k ,But The File Is [ %s ] k " % (may_size, file_size)
            public.color_msg(31, msg, 40)
            return False


        #如果文件存在，并且md5一样  有文件  {"status":0,"seek":0}
        #如果文件存在，并且md5 不一样      {"status":2,"seek":281273}
        #如果文件不存在                 {"status":1,"seek":0}
        #空间不够                {"status":3,"file":0,"max":0}


        # socket_obj.sendall(bytes(file_info), "utf8")


    # def client_get(self):
    #     pass